/*
 * @Author: yangzonglong
 * @Date: 2021-02-22 13:59:06
 * @version: v1.0.0
 * @Descripttion:
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2021-08-17 10:06:55
 * @Auditor:
 */
import React, { useCallback, useEffect } from 'react';
import { useDrop, DropTargetMonitor } from 'react-dnd';
import classname from 'classnames';
import useFdStore from './../../../../hooks/useFdStore';
import { ActionTypes } from './../../../../reducer';
import CanvasItem from './CanvasItem';
import CanvasItemActions from './CanvasItemActions';
import { ControlProps } from './../../../../interface';
import { createRandomStr, createControlDefOptions, flatControl, controlToTree } from './../../../../util';
import { ControlType, dragSourceMap } from './../../../../config';
import style from './../../../design.module.scss';

function handControlOptions(options: ControlProps['options']) {
  return options?.formItemProps?.name ? {
    ...options,
    formItemProps: {
      ...options?.formItemProps,
      name: Math.random().toString(36).substring(2)
    }
  } : (options?.name ? {
    ...options,
    name: Math.random().toString(36).substring(2)
  } : options);
}

let listLength = 0;

const Canvas = () => {
  const { dispatch, state } = useFdStore();
  const { dragDirection, dragSource, hoverControlId, list, curControl, tableCurrentController, dataListCurrentController, modelListAndModelName } = state;

  useEffect(() => {
    //数量变化的时候给最后一个加选中
    if (list.length !== listLength && list.length) {
      listLength = list.length;
      let _curControl = list[list.length - 1];

      dispatch({
        type: ActionTypes.CHANGE_CONTROL,
        curControl: _curControl,
      });
      // 表格有二级设置页面 需要清除
      if (_curControl.type === 'table') {
        tableCurrentController?.fn?.({});
      }
      if (_curControl.type === 'dataList') {
        dataListCurrentController?.fn?.({});
      }
    }
  }, [dataListCurrentController, dispatch, list, tableCurrentController]);

  const [collect, drop] = useDrop({
    accept: Object.values(ControlType).map(item => 'add_' + item),
    collect: (minoter: DropTargetMonitor) => ({
      isOver: minoter.isOver({ shallow: true }),
      canDrop: minoter.canDrop(),
    }),
  });

  const removeControl = useCallback(() => {
    const flatList = flatControl(list);
    let _list: ControlProps[] = flatList.filter(item => item.id !== curControl?.id);

    if (curControl?.type === ControlType.DATALINK) {
      let name = curControl?.['options']?.['formItemProps']?.['name'];

      _list = _list.map(item => {
        if (item.type === 'input' && item?.options?.inputProps?.bindName === name) {
          return {
            ...item,
            options: {
              ...item.options,
              inputProps: {
                ...item?.options?.inputProps,
                bindName: undefined,
                showFiled: undefined
              }
            }
          };
        } else if (item.type === 'dataLinkComBox' && item?.options?.inputProps?.bindName === name) {
          return {
            ...item,
            options: {
              ...item.options,
              inputProps: {
                ...item?.options?.inputProps,
                bindName: undefined,
                screenConditionRules: []
              }
            }
          };
        } else {
          return item;
        }
      });
    }

    dispatch({
      type: ActionTypes.SYNC_LIST,
      modelListAndModelName,
      list: controlToTree(_list),
      curControl: {} as any,
    });
  }, [list, curControl, dispatch, modelListAndModelName]);

  const copyControl = useCallback(() => {
    const flatList = flatControl(list);

    const addArr: ControlProps[] = [{
      ...curControl,
      id: createRandomStr(curControl!.type),
      type: curControl!.type,
      options: handControlOptions(curControl?.options)
    }];

    const each = (id: string, newId: string) => {
      flatList.forEach(item => {
        // 找到子级
        if (item.parentId === id) {
          const _id = createRandomStr(item.type);

          addArr.push({
            ...item,
            id: _id,
            parentId: newId,
            options: handControlOptions(item?.options)
          });

          each(item.id, _id);
        }
      });
    };

    each(curControl!.id, addArr[0].id);

    dispatch({
      modelListAndModelName,
      type: ActionTypes.SYNC_LIST,
      list: controlToTree(flatList.concat(addArr)),
      curControl: {} as any,
    });
  }, [list, curControl, dispatch, modelListAndModelName]);

  const editControl = useCallback((type: string) => {
    const index = list.findIndex((item) => item.id === curControl?.id);

    const _control = createControlDefOptions(type, {
      name: curControl?.options?.formItemProps.name,
      width: curControl?.options?.formItemProps?.style.width, id: curControl?.id
    });
    let _list = [...list];

    _list.splice(index, 1, _control);

    dispatch({
      type: ActionTypes.SYNC_LIST,
      modelListAndModelName,
      list: _list,
      curControl: {} as any,
    });

  }, [curControl, dispatch, modelListAndModelName, list]);

  const moveControl = useCallback(
    (id: string, toId: string) => {
      const flatList = flatControl(list);
      const index = flatList.findIndex(item => item.id === id);
      const toIndex = flatList.findIndex(item => item.id === toId);

      if(index === toIndex) return;
      
      let arr: ControlProps[] = [];

      // 同级，视图拖动改变位置
      if ((flatList[index].parentId || '') === (flatList[toIndex].parentId || '')) {
        flatList.forEach((item, i) => {
          if (i === toIndex) {
            if (toIndex < index) {
              arr.push(flatList[index]);
              arr.push(flatList[toIndex]);
            } else {
              arr.push(flatList[toIndex]);
              arr.push(flatList[index]);
            }
          } else if (i === index) {
          } else {
            arr.push(item);
          }
        });
      } else { // 增加子元素
        arr = flatList.concat();
        arr[index].parentId = arr[toIndex].id;
      }

      dispatch({
        type: ActionTypes.SYNC_LIST,
        modelListAndModelName,
        list: controlToTree(arr)
      });
    },
    [dispatch, modelListAndModelName, list]
  );

  const setActiveControl = useCallback(
    (control: ControlProps) => {
      tableCurrentController?.fn?.({});
      dataListCurrentController?.fn?.({});
      dispatch({
        type: ActionTypes.CHANGE_CONTROL,
        curControl: control,
      });
    },
    [dataListCurrentController, dispatch, tableCurrentController]
  );

  // 设置拖动相关信息，需延迟时间
  const setDragReducer = useCallback(
    (data: Record<string, any>) => {
      dispatch(data);
    },
    [dispatch]
  );

  const createControl = (children: ControlProps[]): any => {
    return children.map((item, index) => {
      const options = {
        index,
        item,
        moveControl,
        setActiveControl,
        setDragReducer,
        dragDirection,
        dragSource,
        hoverControlId,
        curControl,
        key: item.id
      };
      
      if (item.children) {
        return <CanvasItem {...options}>{createControl(item.children)}</CanvasItem>;
      }
      return <CanvasItem {...options} />;
    });
  };


  return (
    <div
      id="canvas"
      ref={drop}
      className={classname(style.canvas, {
        [style.form]: true,
        [style.active]: collect.canDrop && collect.isOver && dragSource === dragSourceMap.MENU,
      })}
    >
      {list.length ? createControl(list) : (
        <p className={style.noListTip}>从左侧拖拽或点击来添加字段</p>
      )}

      {curControl?.id && !dragSource && (
        <CanvasItemActions
          curControl={curControl}
          editControl={editControl}
          removeControl={removeControl}
          copyControl={copyControl} />
      )}
    </div>
  );
};

export default Canvas;
